import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"
import {
  FlatList,
  ImageStyle,
  Modal,
  Pressable,
  ScrollView,
  TextStyle,
  View,
  ViewStyle,
} from "react-native"
import { Image } from "expo-image"
import { router, useLocalSearchParams } from "expo-router"

import { AgentInput, MessageItem } from "@/components"
import { Screen } from "@/components/Screen"
import { Text } from "@/components/Text"
import { useStores } from "@/models/helpers/useStores"
import { type AgentModel as AgentDescriptor } from "@/services/api/agents"
import { CompletionReq, getConversation, Message } from "@/services/api/conversations"
import { startConversationCompletion } from "@/services/sse/conversations"
import { useAppTheme } from "@/theme/context"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { useHeader } from "@/utils/useHeader"

type LocalMessage = Message & { isStreaming?: boolean }

interface AgentSwitcherProps {
  agent: AgentDescriptor
  agents: AgentDescriptor[]
  onSelect: (agent: AgentDescriptor) => void
}

const ChatPage: FC = function ChatPage() {
  const { agentId, conversationId } = useLocalSearchParams<{
    agentId: string
    conversationId: string
  }>()
  const { agentsStore } = useStores()
  const { themed } = useAppTheme()

  const fallbackAgent: AgentDescriptor = (agentsStore.modelsByName.get(agentId) as
    | AgentDescriptor
    | undefined) ?? {
    model: agentId ?? "未知模型",
    iconUrl: "",
    brief: "暂无简介",
    requestModalities: [],
  }
  const [selectedAgent, setSelectedAgent] = useState<AgentDescriptor>(() => fallbackAgent)

  const initialConversationId =
    typeof conversationId === "string" && conversationId !== "new" ? conversationId : undefined

  const [currentConversationId, setCurrentConversationId] = useState<string | undefined>(
    initialConversationId,
  )
  const [messages, setMessages] = useState<LocalMessage[]>([])
  const [isLoading, setIsLoading] = useState(false)

  type ConversationPageState = { conversationId: string; size: number; last?: string }
  const [requestPayload, setRequestPayload] = useState<ConversationPageState | undefined>(
    initialConversationId
      ? {
          conversationId: initialConversationId,
          size: 10,
        }
      : undefined,
  )
  const [hasMore, setHasMore] = useState<boolean>(true)

  const flatListRef = useRef<FlatList>(null)
  const clientsRef = useRef<Record<string, ReturnType<typeof startConversationCompletion> | null>>(
    {},
  )
  const responseIdRef = useRef<Record<string, string>>({})

  useHeader({
    title: selectedAgent.model,
    leftIcon: "back",
    onLeftPress: router.back,
  })

  useEffect(() => {
    if (conversationId === "new") {
      return
    }
    getData()
  }, [conversationId])

  useEffect(() => {
    agentsStore.fetchModels(undefined, { force: false })
  }, [agentsStore])

  useEffect(() => {
    const refreshed = agentsStore.models.find((item) => item.model === selectedAgent.model)
    if (refreshed && refreshed !== selectedAgent) {
      setSelectedAgent(refreshed)
    }
  }, [agentsStore.models, selectedAgent])

  useEffect(() => {
    const existing = agentsStore.models.find((item) => item.model === agentId)
    if (existing) {
      if (existing !== selectedAgent) {
        setSelectedAgent(existing)
      }
      return
    }

    if (typeof agentId === "string" && agentId && agentId !== selectedAgent.model) {
      setSelectedAgent({
        model: agentId,
        iconUrl: "",
        brief: "暂无简介",
        requestModalities: [],
      })
    }
  }, [agentId, agentsStore.models, selectedAgent])

  const getData = () => {
    if (!requestPayload) return

    getConversation(requestPayload).then((res) => {
      console.log("get conversation", res.data?.data)
      setRequestPayload((prev) =>
        prev
          ? {
              ...prev,
              last: res.data?.data.last ?? undefined,
            }
          : prev,
      )
      setHasMore(Boolean(res.data?.data.hasMore))
      const incoming = res.data?.data?.messages ?? []
      if (incoming.length) {
        const reversed = incoming.slice().reverse()
        setMessages((prev) => [...reversed, ...prev])
        const resolvedConversationId = reversed[0]?.conversationId
        if (resolvedConversationId) {
          setCurrentConversationId(resolvedConversationId)
          setRequestPayload((prev) => {
            const size = prev?.size ?? 10
            return {
              conversationId: resolvedConversationId,
              size,
              last: undefined,
            }
          })
        }
      }
    })
  }

  // 使用useCallback优化scrollToBottom函数
  const scrollToBottom = useCallback(() => {
    setTimeout(() => {
      flatListRef.current?.scrollToEnd({ animated: true })
    }, 100)
  }, [])

  useEffect(() => {
    return () => {
      Object.values(clientsRef.current).forEach((client) => client?.disconnect())
      clientsRef.current = {}
    }
  }, [])

  const generateId = () => `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`

  const buildCompletionPayload = useCallback(
    (latest: LocalMessage): CompletionReq => {
      if (!latest || !(latest.contents ?? []).length) {
        return { messages: [] }
      }

      return {
        messages: [
          {
            conversationId: latest.conversationId ?? currentConversationId,
            messageId: latest.messageId,
            model: latest.model ?? selectedAgent.model,
            contents: latest.contents,
            indexInConv: latest.indexInConv ?? 0,
            direction: latest.direction ?? "ask",
            state: latest.state ?? (latest.isStreaming ? "pending" : "done"),
          },
        ],
      }
    },
    [selectedAgent.model, currentConversationId],
  )

  const deriveMessageState = useCallback((serverMessage: Message): Message => {
    if (serverMessage.state === "pending") {
      const creationsComplete = serverMessage.contents?.some((content) =>
        content.creationBlock?.creations?.every((creation) => creation.state === "done"),
      )
      if (creationsComplete) {
        return { ...serverMessage, state: "done" }
      }
    }
    return serverMessage
  }, [])

  const startCompletion = useCallback(
    (
      latestMessage: LocalMessage,
      placeholderId: string,
      options?: {
        onFinish?: () => void
      },
    ) => {
      const payload = buildCompletionPayload(latestMessage)
      if (!payload.messages.length) {
        options?.onFinish?.()
        return
      }

      clientsRef.current[placeholderId] = startConversationCompletion(payload, {
        onMessage: (event) => {
          const serverMessage = event?.data?.message

          console.log("Received server message:", serverMessage)
          if (!serverMessage) return

          const normalized = deriveMessageState(serverMessage)

          const resolvedId = normalized.messageId ?? placeholderId
          responseIdRef.current[placeholderId] = resolvedId

          if (normalized.conversationId) {
            setCurrentConversationId((prev) => {
              if (prev === normalized.conversationId) return prev
              setRequestPayload((prev) =>
                prev
                  ? {
                      ...prev,
                      conversationId: normalized.conversationId!,
                      last: undefined,
                    }
                  : {
                      conversationId: normalized.conversationId!,
                      size: 10,
                      last: undefined,
                    },
              )
              return normalized.conversationId
            })
          }

          setMessages((prev) =>
            prev.map((msg) =>
              msg.messageId === placeholderId || msg.messageId === resolvedId
                ? {
                    ...msg,
                    ...normalized,
                    messageId: resolvedId,
                    isStreaming: normalized.state !== "done",
                  }
                : msg,
            ),
          )
          scrollToBottom()
        },
        onComplete: () => {
          const resolvedId = responseIdRef.current[placeholderId]
          setMessages((prev) =>
            prev.map((msg) =>
              msg.messageId === placeholderId || (resolvedId && msg.messageId === resolvedId)
                ? { ...msg, isStreaming: false, state: "done" }
                : msg,
            ),
          )
          clientsRef.current[placeholderId]?.disconnect()
          delete clientsRef.current[placeholderId]
          delete responseIdRef.current[placeholderId]
          options?.onFinish?.()
        },
        onError: (error) => {
          console.warn("Completion error:", error)
          const resolvedId = responseIdRef.current[placeholderId]
          setMessages((prev) =>
            prev.map((msg) =>
              msg.messageId === placeholderId || (resolvedId && msg.messageId === resolvedId)
                ? { ...msg, isStreaming: false, state: "failed" }
                : msg,
            ),
          )
          clientsRef.current[placeholderId]?.disconnect()
          delete clientsRef.current[placeholderId]
          delete responseIdRef.current[placeholderId]
          options?.onFinish?.()
        },
      })
    },
    [buildCompletionPayload, deriveMessageState, scrollToBottom],
  )

  const sendTextMessage = useCallback(
    async (input: string) => {
      const trimmed = input.trim()
      if (!trimmed) return

      const userId = generateId()
      const userMessage: LocalMessage = {
        conversationId: currentConversationId,
        messageId: userId,
        model: selectedAgent.model,
        contents: [
          {
            contentType: "text",
            textBlock: { text: trimmed },
          },
        ],
        direction: "ask",
        state: "done",
      }

      const placeholderId = `${userId}-reply`
      const placeholder: LocalMessage = {
        conversationId: currentConversationId,
        messageId: placeholderId,
        model: selectedAgent.model,
        contents: [],
        direction: "answer",
        state: "pending",
        isStreaming: true,
      }

      const completions: { latest: LocalMessage; placeholderId: string }[] = []

      setIsLoading(true)
      setMessages((prev) => {
        completions.push({ latest: userMessage, placeholderId })
        return [...prev, userMessage, placeholder]
      })

      scrollToBottom()

      completions.forEach(({ latest, placeholderId }) =>
        startCompletion(latest, placeholderId, {
          onFinish: () => setIsLoading(false),
        }),
      )
    },
    [selectedAgent.model, currentConversationId, scrollToBottom, startCompletion],
  )

  const sendImages = useCallback(
    (uploaded: string[]) => {
      if (!uploaded.length) return

      const completions: { latest: LocalMessage; placeholderId: string }[] = []

      setMessages((prev) => {
        let draft = [...prev]

        uploaded.forEach((url) => {
          const imageId = generateId()
          const userMessage: LocalMessage = {
            conversationId: currentConversationId,
            messageId: imageId,
            model: selectedAgent.model,
            contents: [
              {
                contentType: "image",
                imageBlock: { image: { url } },
              },
            ],
            direction: "ask",
            state: "done",
          }

          const placeholderId = `${imageId}-reply`
          const placeholder: LocalMessage = {
            conversationId: currentConversationId,
            messageId: placeholderId,
            model: selectedAgent.model,
            contents: [],
            direction: "answer",
            state: "pending",
            isStreaming: true,
          }

          completions.push({ latest: userMessage, placeholderId })

          draft = [...draft, userMessage, placeholder]
        })

        return draft
      })

      scrollToBottom()
      completions.forEach(({ latest, placeholderId }) => startCompletion(latest, placeholderId))
    },
    [selectedAgent.model, currentConversationId, scrollToBottom, startCompletion],
  )

  // 使用useCallback优化keyExtractor
  const keyExtractor = (item: Message, index: number) => item.messageId ?? `${item.model}-${index}`

  return (
    <Screen preset="fixed" contentContainerStyle={$styles.flex1} keyboardOffset={100}>
      <FlatList
        ref={flatListRef}
        data={messages}
        renderItem={({ item }) => <MessageItem message={item} showTimestamp={false} />}
        keyExtractor={keyExtractor}
        style={themed($messagesList)}
        contentContainerStyle={themed($messagesContainer)}
        onContentSizeChange={scrollToBottom}
      />

      <AgentInput onSend={sendTextMessage} onImagesChange={sendImages} isLoading={isLoading} />
    </Screen>
  )
}

// Messages styles
const $messagesList: ThemedStyle<ViewStyle> = ({ colors }) => ({
  flex: 1,
  backgroundColor: colors.background,
})

const $messagesContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  paddingHorizontal: spacing.md,
  paddingVertical: spacing.sm,
})

export default ChatPage
